package org.fin.session.statement;

import com.mysql.cj.util.StringUtils;
import org.fin.config.BoundSql;
import org.fin.exception.NoSuchTypeException;
import org.fin.exception.PersistenceFrameworkException;
import org.fin.utils.ParameterMapping;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.List;

public class ParameterHandler {

  private final Object param;
  private final Class<?> paramterTypeCls;

  /**
   * 从参数获取参数类型，如paramterType有配置则需要判断是否匹配
   */
  public ParameterHandler(String paramterType, Object param) {
    if (StringUtils.isEmptyOrWhitespaceOnly(paramterType)) {
      this.paramterTypeCls = param.getClass();
    }else {
      this.paramterTypeCls = getParameterCls(paramterType);
      if (param.getClass() != this.paramterTypeCls) {
        throw new PersistenceFrameworkException(
            String.format("paramterType[%s]与传入参数类型[%s]不匹配",
                          this.paramterTypeCls.getName(),
                          param.getClass().getName()
        ));
      }
    }

    this.param = param;
  }

  /**
   * 设置PreparedStatement的参数
   */
  public void handle(BoundSql boundSql, PreparedStatement preparedStatement) {


    // 获取sql对应的参数名，进行遍历并将获取到的参数值设置在preparedStatement中
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    for (int i = 0; i < parameterMappings.size(); i++) {
      ParameterMapping parameterMapping = parameterMappings.get(i);
      String fieldName = parameterMapping.getContent();

      String getterName = getGetterMethodName(fieldName);


      try {

        Method getter = paramterTypeCls.getMethod(getterName);
        Object value = getter.invoke(param);
        preparedStatement.setObject(i + 1, value);

      }catch (IllegalAccessException e) {
        throw new PersistenceFrameworkException(
            param.getClass().getName() + "." + getterName + "(): getter is not accessible.", e);
      } catch (NoSuchMethodException e) {
        throw new PersistenceFrameworkException(
            param.getClass().getName() + "." + getterName + "(): getter is not exists.", e);
      } catch (InvocationTargetException e) {
        throw new RuntimeException(param.getClass().getName() + "." + getterName + "(): getter throws an exception.", e);
      } catch (SQLException e) {
        throw new PersistenceFrameworkException(e);
      }

    }
  }

  /**
   * 拼接getter方法名
   * @param content   字段名
   * @return          getter方法名
   */
  private String getGetterMethodName(String content) {
    return "get" + content.substring(0, 1).toUpperCase() + content.substring(1);
  }

  /**
   * 获取参数类型字节码对象
   */
  private Class<?> getParameterCls(String paramterType) {
    try {
      return Class.forName(paramterType);
    } catch (ClassNotFoundException e) {
      throw new NoSuchTypeException("找不到对应的参数类型: " + paramterType, e);
    }
  }
}
